﻿using JetBrains.Annotations;
using StreetPacMan.Server.Facade;
using System.Linq;

namespace StreetPacMan.Server
{
    public interface IServerFacade
    {
        CreateGameResult CreateGame(CreateGameParameters parameters);
        JoinGameResult JoinGame(JoinGameParameters parameters);
        ServerPollResult UpdateMyWhereabouts(ServerPollParameters parameters);
        GetGameStateResult GetGameState(GetGameStateParameters parameters);
        GetAllGamesResult GetAllGames();
        void REMOVEME_CopyApplesFromOneGameToAnother(REMOVEME_CopyApplesFromOneGameToAnotherParameters parameters);
        void SendGameMessage(SendGameMessageParameters parameters);
        GetAllEventsResults GetAllEvents(GetAllEventsParameters parameters);
        void DeleteGame(DeleteGameParameters parameters);
    }

    [UsedByIoc]
    public class ServerFacade : IServerFacade
    {
        private readonly IConnectionProvider _ConnectionProvider;
        private readonly IGameManagementHandler _GameManagementHandler;
        private readonly IPlayerLocationChangedHandler _PlayerLocationChangedHandler;
        private readonly IStatusMessageGenerator _StatusMessageGenerator;

        public ServerFacade(
            IConnectionProvider connectionProvider,
            IGameManagementHandler gameManagementHandler,
            IPlayerLocationChangedHandler playerLocationChangedHandler,
            IStatusMessageGenerator statusMessageGenerator)
        {
            _ConnectionProvider = connectionProvider;
            _GameManagementHandler = gameManagementHandler;
            _PlayerLocationChangedHandler = playerLocationChangedHandler;
            _StatusMessageGenerator = statusMessageGenerator;
        }

        public void REMOVEME_CopyApplesFromOneGameToAnother(REMOVEME_CopyApplesFromOneGameToAnotherParameters argumetns)
        {
            using (var dbConnection = _ConnectionProvider.GetConnection())
            using (var pacManDataContext = new PacManDataContext(dbConnection))
            {
                pacManDataContext.Apples.DeleteAllOnSubmit(pacManDataContext.Apples.Where(x => x.GameId == argumetns.DestinationGameId));

                var apples = pacManDataContext
                    .Apples
                    .Where(x => x.GameId == argumetns.OriginGameId)
                    .ToArray();
                var newApples = apples
                    .Select(x => new Apple
                    {
                        GameId = argumetns.DestinationGameId,
                        GeoLat = x.GeoLat,
                        GeoLon = x.GeoLon,
                        Kind = x.Kind,
                        State = x.State,
                        RemovedAt = x.RemovedAt
                    })
                    .ToArray();
                pacManDataContext.Apples.InsertAllOnSubmit(newApples);

                pacManDataContext.SubmitChanges();
            }
        }

        public GetAllGamesResult GetAllGames()
        {
            return new GetAllGamesResult(_GameManagementHandler.GetAllGames());
        }

        public void SendGameMessage(SendGameMessageParameters gameStateParameters)
        {
            _GameManagementHandler.SendGameMessage(gameStateParameters);
        }

        public CreateGameResult CreateGame(CreateGameParameters parameters)
        {
            return new CreateGameResult(_GameManagementHandler.CreateGame(parameters.GameName).Id);
        }

        public JoinGameResult JoinGame(JoinGameParameters parameters)
        {
            return new JoinGameResult(_GameManagementHandler.JoinGame(parameters.GameName, parameters.PlayerName, parameters.Role).Id);
        }

        public GetGameStateResult GetGameState(GetGameStateParameters gameStateParameters)
        {
            return _StatusMessageGenerator.CreateInitialGameMessagesFor(gameStateParameters.EntityId);
        }

        public GetAllEventsResults GetAllEvents(GetAllEventsParameters parameters)
        {
            return new GetAllEventsResults(_GameManagementHandler.GetAllEvents(parameters.GameId));
        }

        public void DeleteGame(DeleteGameParameters parameters)
        {
            _GameManagementHandler.DeleteGame(parameters.GameName);
        }

        public ServerPollResult UpdateMyWhereabouts(ServerPollParameters serverPollParameters)
        {
            _PlayerLocationChangedHandler.Handle(serverPollParameters);
            return _StatusMessageGenerator.CreateUpdateMessageFor(serverPollParameters.EntityId, serverPollParameters.UpdateMeForTheLastXSeconds);
        }
    }
}
